﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System.Collections.ObjectModel;

namespace SimpleChat.ViewModel
{
    /// <summary>
    /// This class contains properties that the main View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm/getstarted
    /// </para>
    /// </summary>
    public class MainViewModel : ViewModelBase
    {
        #region Properties
        public string Title { get { return "NetAccess v3.0-alpha Demo : SimpleChat"; } }

        #region ChatMessages
        /// <summary>
        /// The <see cref="ChatMessages" /> property's name.
        /// </summary>
        internal const string ChatMessagesPropertyName = "ChatMessages";

        private SafeObservableCollection<ChatContentMessage> _storeChatMessages = new SafeObservableCollection<ChatContentMessage>();

        /// <summary>
        /// Gets the ChatMessages property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public SafeObservableCollection<ChatContentMessage> ChatMessages
        {
            get
            {
                return _storeChatMessages;
            }
            /*
            set
            {
                if (_storeChatMessages == value)
                {
                    return;
                }

                _storeChatMessages = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(ChatMessagesPropertyName);
            }*/
        }
        #endregion

        #region InputMessage
        /// <summary>
        /// The <see cref="InputMessage" /> property's name.
        /// </summary>
        public const string InputMessagePropertyName = "InputMessage";

        private string _storeInputMessage = "";

        /// <summary>
        /// Gets the InputMessage property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public string InputMessage
        {
            get
            {
                return _storeInputMessage;
            }

            set
            {
                if (_storeInputMessage == value)
                {
                    return;
                }

                var oldValue = _storeInputMessage;
                _storeInputMessage = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(InputMessagePropertyName);
            }
        }
        #endregion

        #region Users
        /// <summary>
        /// The <see cref="Users" /> property's name.
        /// </summary>
        internal const string UsersPropertyName = "Users";

        private SafeObservableCollection<UserListMessage> _storeUsers = new SafeObservableCollection<UserListMessage>();

        /// <summary>
        /// Gets the Users property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public SafeObservableCollection<UserListMessage> Users
        {
            get
            {
                return _storeUsers;
            }
            /*
            set
            {
                if (_storeChatMessages == value)
                {
                    return;
                }

                _storeChatMessages = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(ChatMessagesPropertyName);
            }*/
        }
        #endregion
        #endregion

        #region Commands
        // Commands
        public RelayCommand SendMessageCommand { get; private set; }
        public RelayCommand JoinServerCommand { get; private set; }
        public RelayCommand CreateNewServerCommand { get; private set; }
        #endregion

        #region Fields

        private Network.Server _server;
        private Network.Client _client;

        #endregion

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel()
            : base(Messenger.Default)
        {
            if (IsInDesignMode)
            {
                // Code runs in Blend --> create design time data.
            }
            else
            {
                CreateNewServerCommand = new RelayCommand(CreateNewServerCommandHandler);
                JoinServerCommand = new RelayCommand(JoinServerCommandHandler);
                SendMessageCommand = new RelayCommand(SendmessageCommandHandler);
                Messenger.Default.Register<ChatContentMessage>(this, HandleChatContentMessage);
                Messenger.Default.Register<UserListMessage>(this, HandleUserListMessage);
            }
        }
        
        #region Command Action
        private void SendmessageCommandHandler()
        {
            if (_client == null || _client.State != NetAccess.Client.ClientState.Connected)
            {
                MessengerInstance.Send(new ChatContentMessage(String.Format("Unable to send message. You are not connected to a server"), ChatContentMessage.MessageType.System));
                return;
            }
            
            _client.SendChat(InputMessage);
            InputMessage = "";
        }

        private void JoinServerCommandHandler()
        {
            MessengerInstance.Send(new WindowDialogMessage<bool?>("JoinServer", (result) =>
                {
                    if (!result.HasValue || !result.Value)
                        return;

                    ChatMessages.Clear();

                    _client = new Network.Client(MessengerInstance, ViewModelLocator.JoinServerStatic.Username);
                    _client.Connect(ViewModelLocator.JoinServerStatic.SelectedService);
                }));
        }

        private void CreateNewServerCommandHandler()
        {
            MessengerInstance.Send(new WindowDialogMessage<bool?>("CreateServer", (result) =>
                {
                    if(!result.HasValue || !result.Value)
                        return;

                    // Initialize and start the server
                    ChatMessages.Clear();
                    _server = new Network.Server(MessengerInstance, ViewModelLocator.CreateServerStatic.ServerName, ViewModelLocator.CreateServerStatic.ServerPassword);
                    _server.Start();

                    _client = new Network.Client(MessengerInstance, ViewModelLocator.CreateServerStatic.Username, ViewModelLocator.CreateServerStatic.ServerPassword);
                    _client.Connect("127.0.0.1");
                }));
        }
        #endregion

        private void HandleUserListMessage(UserListMessage message)
        {
            if (message.Type == UserListMessage.MessageType.Add)
                Users.Add(message);
            else if (message.Type == UserListMessage.MessageType.Clear)
                Users.Clear();
            else
                Users.Remove(message);
        }

        private void HandleChatContentMessage(ChatContentMessage message)
        {
            ChatMessages.Add(message);
        }

        public override void Cleanup()
        {
            base.Cleanup();
        }
    }
}
